package com.core.managers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.core.utils.GlobalConstants;
import com.core.utils.KeyValueDictionary;
import com.model.KeyValue;

/**
 * @uml.dependency   supplier="com.core.utils.GlobalConstants"
 */
public class SessionManager {

	public static final String                     SM_ATTRIBUTE_CONTEXT_PATH      = "SM_ATTRIBUTE_CONTEXT_PATH";
	public static final String                     SM_ATTRIBUTE_REQUEST_URI       = "SM_ATTRIBUTE_REQUEST_URI";
	public static final String                     SM_ATTRIBUTE_REQUEST_QUERY     = "SM_ATTRIBUTE_REQUEST_QUERY";
	public static final String                     SM_ATTRIBUTE_USER_CONTEXT_NAME = "SM_ATTRIBUTE_USER_CONTEXT_NAME";

	private static SessionManager                  Instance                       = null;
	private String                                 lastExecutedURL                = null;
	private Map <String, String>                   lastExecutedServletQuery       = new HashMap <String, String>();
	private Map <String, HashMap <String, String>> lastServletQueryParams         = new TreeMap <String, HashMap <String, String>>();


	private KeyValueDictionary                     attributes                     = new KeyValueDictionary();

	// HttpServletRequest request;
	private HttpServletResponse                    response;
	private HttpServletRequest                     pageRequest;
	private HttpServletResponse                    pageResponse;



	public String userLocale () {

		return "ru_RU";
	}



	public static SessionManager sharedInstance () {

		if ( Instance == null ) {
			Instance = new SessionManager();
		}
		return Instance;
	}



	public void logout () {

		this.setAttributeValue(GlobalConstants.SM_ATTRIBUTE_IS_AUTHORIZED, null);
	}



	public boolean isAuthenticated () {

		final String isAuthenticatedStr = (String) this.getAttributeValue(GlobalConstants.SM_ATTRIBUTE_IS_AUTHORIZED);
		return "true".equalsIgnoreCase(isAuthenticatedStr);

	}



	public void setAttributeValue ( final String name,
	                                final Object value ) {

		attributes.put(name, value);

	}



	public Object getAttributeValue ( final String name ) {

		return attributes.get(name);
	}



	public Object getUserContextName () {

		return this.getAttributeValue(SessionManager.SM_ATTRIBUTE_USER_CONTEXT_NAME);
	}



	public static void setContext ( final Object contextName ) {

		SessionManager sessionManager = SessionManager.sharedInstance();
		sessionManager.setUserContext(contextName);
	}



	public void setUserContext ( final Object contextName ) {

		this.setAttributeValue(SessionManager.SM_ATTRIBUTE_USER_CONTEXT_NAME, contextName);
	}



	public static void addContext ( final Object contextName ) {

		SessionManager sessionManager = SessionManager.sharedInstance();
		sessionManager.addUserContext(contextName);
	}



	public void addUserContext ( final Object contextName ) {

		final String userContextName = (String) this.getAttributeValue(SessionManager.SM_ATTRIBUTE_USER_CONTEXT_NAME);

		final List <String> arrayList = new ArrayList <String>();
		String[] simpleList = null;
		if ( userContextName != null ) {
			simpleList = userContextName.split(";");
			for ( int i = 0; i < simpleList.length; i++ ) {
				arrayList.add(simpleList[i]);
			}
		} else {
		}
		arrayList.add((String) contextName);

		Boolean separatorNeed = false;
		StringBuilder stringBuilder = new StringBuilder();
		if ( arrayList != null ) {
			for ( int i = 0; i < arrayList.size(); i++ ) {
				if ( separatorNeed ) {
					stringBuilder.append(';');
				}
				stringBuilder.append(arrayList.get(i));
				separatorNeed = true;
			}
		}

		this.setAttributeValue(SessionManager.SM_ATTRIBUTE_USER_CONTEXT_NAME, stringBuilder.toString());
	}



	private void pushLastExecutedURL () {

		String servletName = this.servletName();
		String servletQuery = this.currentRequestQueryString();

		if ( servletName != null ) {
			if ( servletQuery != null ) {
				lastExecutedURL = String.format("%s?%s", servletName, servletQuery);
			} else {
				lastExecutedURL = servletName;
			}
		}

		lastExecutedServletQuery.put(servletName, servletQuery);
		this.parseServletQueryParams(servletName, servletQuery);
	}



	public String lastExecutedURL () {

		return this.lastExecutedURL;
	}



	public void clearUserContextName () {

		this.setUserContext(null);
	}



	public HttpServletRequest getPageRequest () {

		return pageRequest;
	}



	public void setPageRequest ( HttpServletRequest pageRequest ) {

		this.pageRequest = pageRequest;
	}



	public HttpServletResponse getPageResponse () {

		return pageResponse;
	}



	public void setPageResponse ( final HttpServletResponse pageResponse ) {

		this.pageResponse = pageResponse;
	}



	public void setRequest ( final HttpServletRequest request ) {

		this.setAttributeValue(SessionManager.SM_ATTRIBUTE_REQUEST_QUERY, request.getQueryString());
		this.setAttributeValue(SessionManager.SM_ATTRIBUTE_CONTEXT_PATH, request.getContextPath());
		this.setAttributeValue(SessionManager.SM_ATTRIBUTE_REQUEST_URI, request.getRequestURI());

		this.pushLastExecutedURL();

	}



	public String lastExecutedServletQuery ( final String servletName ) {

		String result = null;
		String key = servletName;
		if ( key == null ) {
			key = this.servletName();
		}
		if ( key != null ) {
			boolean containsKey = lastExecutedServletQuery.containsKey(key);
			if ( containsKey ) {
				String query = lastExecutedServletQuery.get(key);
				if ( query != null ) {
					result = String.format("%s?%s", key, query);
				}
			}
		}
		return result;
	}



	public Boolean allowRedirection () {

		String link = String.format("%s?%s", this.servletName(), this.currentRequestQueryString());
		String lastRedirection = this.lastExecutedServletQuery(null);
		return (!link.equalsIgnoreCase(lastRedirection));
	}



	public HttpServletResponse getResponse () {

		return response;
	}



	public void setResponse ( final HttpServletResponse response ) {

		this.response = response;
	}



	public String currentRequestQueryString () {

		return (String) this.getAttributeValue(SessionManager.SM_ATTRIBUTE_REQUEST_QUERY);
	}



	public String currentPageRequestQueryString () {

		return this.pageRequest.getQueryString();
	}



	public String servletContextPath ( final HttpServletRequest request ) {

		return request.getServletPath();
	}



	public String servletName () {


		String servletPath = (String) this.getAttributeValue(SessionManager.SM_ATTRIBUTE_CONTEXT_PATH);
		if ( servletPath == null ) {
			return null;
		}

		if ( servletPath.isEmpty() ) {
			return null;
		}

		final String requestURI = (String) this.getAttributeValue(SessionManager.SM_ATTRIBUTE_REQUEST_URI);
		String result = requestURI.substring(servletPath.length());
		result = result.replace('/', ' ').trim();

		return result;
	}



	protected void parseServletQueryParams ( final String servletName,
	                                         final String servletQuery ) {

		if ( servletName == null ) {
			return;
		}
		HashMap <String, String> map = new HashMap <String, String>();
		if ( servletQuery != null ) {

			String[] params = servletQuery.split("&");
			for ( int i = 0; i < params.length; i++ ) {
				String[] mapValues = params[i].split("=");
				if ( mapValues.length == 2 ) {
					map.put(mapValues[0], mapValues[1]);
				}
			}
		}
		lastServletQueryParams.put(servletName, map);
	}



	public KeyValue servletParamValue ( final String servletName,
	                                    final String servletParam,
	                                    final String nullFormat ) {

		KeyValue result = null;
		if ( servletName != null ) {
			HashMap <String, String> map = lastServletQueryParams.get(servletName);
			if ( map != null ) {
				String value = map.get(servletParam);
				if ( value != null ) {
					result = new KeyValue(servletParam, value);
				} else {
					if ( nullFormat != null ) {
						result = new KeyValue(servletParam, nullFormat);
					}
				}
			}
		}
		return result;
	}



	public void removeCookie ( final HttpServletResponse response,
	                           final String cookieName ) {

		this.addCookie(response, cookieName, "", 0);
	}



	public String cookieValue ( final HttpServletRequest request,
	                            final String cookieName ) {

		String result = null;
		Cookie[] cookies = request.getCookies();
		if ( cookies == null ) {
			return result;
		}

		for ( Cookie cookie : cookies ) {
			String name = cookie.getName();
			if ( cookieName.equalsIgnoreCase(name) ) {
				result = cookie.getValue();
				break;
			}
		}

		return result;
	}



	public void addCookie ( final HttpServletResponse response,
	                        final String cookieName,
	                        final String cookieValue,
	                        final int expiration ) {

		Cookie cookie = new Cookie(cookieName, cookieValue);
		cookie.setPath("/");
		cookie.setMaxAge(expiration);
		response.addCookie(cookie);
	}

}
